<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>变量的解构赋值</title>
</head>

<body>
    <script>
        // ES6 允许按照一定模式，从数组和对象中提取值，对变量进行赋值，这被称为解构（Destructuring）。

        // 不解构的赋值
        // let a = 1
        // let b = 2
        // let c = 3
        // // 解构后的赋值
        // let [e, f, g] = [1, 2, 3]

        // //本质上，这种写法属于“模式匹配”，只要等号两边的模式相同，左边的变量就会被赋予对应的值。下面是一些使用嵌套数组进行解构的例子。
        // let [foo, [
        //     [bar], baz
        // ]] = [1, [
        //     [2], 3
        // ]];


        // let [head, ...tail] = [1, 2, 3, 4];
        // let [x, y, ...z] = ['a'];

        // 解构不成功  左边和右边模式不匹配 不成功变量值就等于undefined
        // let [foo] = [];
        // let [bar, foo] = [1];
        // 部分解构 另一种情况是不完全解构，即等号左边的模式，只匹配一部分的等号右边的数组。这种情况下，解构依然可以成功。
        // let [x, y] = [1, 2, 3];
        // // x // 1
        // // y // 2

        // let [a, [b], d] = [1, [2, 3], 4];
        // a // 1
        // b // 2
        // d // 4
        // 如果等号的右边不是数组（或者严格地说，不是可遍历的结构，参见《Iterator》一章），那么将会报错。
        // 报错
        // let [foo] = 1;
        // let [foo] = false;
        // let [foo] = NaN;
        // let [foo] = undefined;
        // let [foo] = null;
        // let [foo] = {}

        // 事实上，只要某种数据结构具有 Iterator 接口，都可以采用数组形式的解构赋值。

        // 默认值 解构赋值允许指定默认值
        // let [foo = true] = [];
        // foo // true

        // // let [x, y = 'b'] = ['a']; // x='a', y='b'
        // let [x, y = 'b'] = ['a', undefined]; // x='a', y='b
        // 注意，ES6 内部使用严格相等运算符（===），判断一个位置是否有值。所以，只有当一个数组成员严格等于undefined，默认值才会生效。
        // let [x = 1] = [undefined];
        // x // 1

        // let [x = 1] = [null];
        // x // null

        // 对象的解构赋值
        // 对象的解构与数组有一个重要的不同。数组的元素是按次序排列的，变量的取值由它的位置决定；而对象的属性没有次序，变量必须与属性同名，才能取到正确的值。
        // let {
        //     bar,
        //     foo
        // } = {
        //     foo: 'aaa',
        //     bar: 'bbb'
        // };
        // foo // "aaa"
        // bar // "bbb"

        // let {
        //     baz
        // } = {
        //     foo: 'aaa',
        //     bar: 'bbb'
        // };
        // baz // undefined  如果解构失败 ，变量的值等于undefined

        // 对象的机构赋值，可以很方便的将现有对象的方法赋值到某个变量

        // let {
        //     log,
        //     sin,
        //     cos
        // } = Math;
        // const {
        //     log
        // } = console
        // log('hello')

        // （3）由于数组本质是特殊的对象，因此可以对数组进行对象属性的解构。
        // let arr = [1, 2, 3];
        // let {
        //     0: first,
        //     [arr.length - 1]: last
        // } = arr;
        // first // 1
        // last // 3
        // 解构赋值的规则是，只要等号右边的值不是对象或数组，就先将其转为对象。由于undefined和null无法转为对象，所以对它们进行解构赋值，都会报错。

        // 函数参数的解构赋值
        // [
        //     [1, 2],
        //     [3, 4]
        // ].map(([a, b]) => a + b);

        // 对象的解构赋值用途
        //1、交换变量的值
        let x = 1;
        let y = 2;

        [x, y] = [y, x];

        //2、从函数返回多个值
        // 函数只能返回一个值，如果要返回多个值，只能将它们放在数组或对象里返回。有了解构赋值，取出这些值就非常方便。
        // 返回一个数组

        // function example() {
        //     return [1, 2, 3];
        // }
        // let [a, b, c] = example();

        // 返回一个对象

        // function example() {
        //     return {
        //         foo: 1,
        //         bar: 2
        //     };
        // }
        // let {
        //     foo,
        //     bar
        // } = example();

        // 函数参数的定义
        // 解构赋值可以方便地将一组参数与变量名对应起来。
        // 参数是一组有次序的值
        // function f([x, y, z]) {

        // }
        // f([1, 2, 3]);

        // // 参数是一组无次序的值
        // function f({
        //     x,
        //     y,
        //     z
        // }) {

        // }
        // f({
        //     z: 3,
        //     y: 2,
        //     x: 1
        // });

        // 4、提取JSON数据 解构赋值对提取 JSON 对象中的数据，尤其有用。
        // let jsonData = {
        //     id: 42,
        //     status: "OK",
        //     data: [867, 5309]
        // };

        // let {
        //     id,
        //     status,
        //     data: number
        // } = jsonData;

        // console.log(id, status, number);
        // 42, "OK", [867, 5309]

        // 5、函数参数默认值

        //6、遍历Map 结构
        // 任何部署了 Iterator 接口的对象，都可以用for...of循环遍历。Map 结构原生支持 Iterator 接口，配合变量的解构赋值，获取键名和键值就非常方便。
        // const map = new Map();
        // map.set('first', 'hello');
        // map.set('second', 'world');

        // for (let [key, value] of map) {
        //     console.log(key + " is " + value);
        // }
        // first is hello
        // second is world

        // 如果只想获取键名，或者只想获取键值，可以写成下面这样。
        // 获取键名
        for (let [key] of map) {
            // ...
        }

        // 获取键值
        for (let [, value] of map) {
            // ...
        }
        //7、输入模块指定方法
        // const { SourceMapConsumer, SourceNode } = require("source-map");
    </script>
</body>

</html>